﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Data.SqlClient;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using hlib.Data;
using SalesSys.Comm.DAL;
using SalesSys.Comm.Utility;

namespace SalesSys.DAL.Base
{
    public class EFContextWarp<T> : EFContextWarpBase where T : DbContext, new()
    {
        protected DbContext internalContext;
        protected override DbContext Context
        {
            get
            {
                if (internalContext != null) return internalContext;
                else return internalContext = new T();
            }
        }
    }
    /// <summary>
    ///     单元操作实现基类
    /// </summary>
    public abstract class EFContextWarpBase
    {
        /// <summary>
        /// 获取 当前使用的数据访问上下文对象
        /// </summary>
        protected abstract DbContext Context { get; }
        ObjectContext objectContext;
        /// <summary>
        /// 获取DbContext关联的ObjectContext
        /// </summary>
        protected ObjectContext ObjectContext
        {
            get
            {
       
                return objectContext ?? (objectContext = ((IObjectContextAdapter)Context).ObjectContext);
            }
        }
        public DataTable SqlQuery(string sql,params DbParameter[] parameters)
        {
            DbHelper db=new DbHelper("WXDB");
            var dt = db.GetDataTable(sql, parameters);
            return dt;
        }  
        /// <summary>
        ///     获取 当前单元操作是否已被提交
        /// </summary>
        public bool IsCommitted { get; private set; }

        // public DbContext DbContext { get { return Context; } }

        /// <summary>
        /// 直接执行sql语句
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public IEnumerable<T> ExeSqlQuery<T>(string sql, params object[] parameters)
        {
            return parameters==null?Context.Database.SqlQuery<T>(sql):Context.Database.SqlQuery<T>(sql,parameters);
        }
        public IEnumerable ExeSqlQuery(Type type, string sql, params object[] parameters)
        {
            return parameters==null?Context.Database.SqlQuery(type,sql):Context.Database.SqlQuery(type,sql, parameters);
        }
        public int ExeSqlCommand(string sql, params object[] parameters)
        {
            return parameters==null?Context.Database.ExecuteSqlCommand(sql):Context.Database.ExecuteSqlCommand(sql, parameters);         
        }

        /// <summary>
        /// 生成数据库创建脚本，基本脚本
        /// </summary>
        /// <returns></returns>
        public string CreateDatabaseScript()
        {
            return ObjectContext.CreateDatabaseScript();
        }
        public ObjectQuery<T> CreateQuery<T>(string queryString, params ObjectParameter[] parameters)  
        {
            return ObjectContext.CreateQuery<T>(queryString, parameters);
        }
        public ObjectSet<T> CreateQuerySet<T>() where T:class
        {
            return ObjectContext.CreateObjectSet<T>();
        }

        /// <summary>
        ///     提交当前单元操作的结果
        /// </summary>
        /// <param name="validateOnSaveEnabled">保存时是否自动验证跟踪实体</param>
        /// <returns></returns>
        public int Commit(bool validateOnSaveEnabled = true)
        {
            if (IsCommitted)
            {
                return 0;
            }
            try
            { 
                int result = Context.SaveChanges(validateOnSaveEnabled);
                IsCommitted = true;
                return result;
            }
            catch (Exception e)   //DbUpdateException
            {
                Log.m.Error("数据提交保存发生异常：" + e);
                throw e;
            }
        }

        /// <summary>
        ///     把当前单元操作回滚成未提交状态
        /// </summary>
        public void Rollback()
        {
            IsCommitted = false;
        }
        /// <summary>
        /// 关闭上下文，不提交
        /// </summary>
        public void Dispose()
        {
            //if (!IsCommitted)
            //{
            //    Commit();
            //}
            Context.Dispose();
        }

        /// <summary>
        ///   为指定的类型返回 System.Data.Entity.DbSet，这将允许对上下文中的给定实体执行 CRUD 操作。
        /// </summary>
        /// <typeparam name="TEntity"> 应为其返回一个集的实体类型。 </typeparam>
        /// <typeparam name="TKey">实体主键类型</typeparam>
        /// <returns> 给定实体类型的 System.Data.Entity.DbSet 实例。 </returns>
        public DbSet<TEntity> Set<TEntity>() where TEntity : class,IDbEntity
        {
            return Context.Set<TEntity>();
        }

        /// <summary>
        ///     注册一个新的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <typeparam name="TKey">实体主键类型</typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterNew<TEntity>(TEntity entity) where TEntity : class, IDbEntity
        {
            EntityState state = Context.Entry(entity).State;
            if (state == EntityState.Detached)
            {
                Context.Entry(entity).State = EntityState.Added;
            }
            IsCommitted = false;
        }

        /// <summary>
        ///     批量注册多个新的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <typeparam name="TKey">实体主键类型</typeparam>
        /// <param name="entities"> 要注册的对象集合 </param>
        public void RegisterNew<TEntity>(IEnumerable<TEntity> entities) where TEntity : class, IDbEntity
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach (TEntity entity in entities)
                {
                    RegisterNew<TEntity>(entity);
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }

        /// <summary>
        ///     注册一个更改的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <typeparam name="TKey">实体主键类型</typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterModified<TEntity>(params TEntity[] entitys) where TEntity : class, IDbEntity
        {
            Context.Update<TEntity>(entitys);
            IsCommitted = false;
        }

        /// <summary>
        /// 使用指定的属性表达式指定注册更改的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity">要注册的类型</typeparam>
        /// <typeparam name="TKey">主键类型</typeparam>
        /// <param name="propertyExpression">属性表达式，包含要更新的实体属性</param>
        /// <param name="entity">附带新值的实体信息，必须包含主键</param>
        public void RegisterModified<TEntity>(Expression<Func<TEntity, object>> propertyExpression, TEntity entity) where TEntity : class, IDbEntity
        {
            Context.Update<TEntity>(propertyExpression, entity);
            IsCommitted = false;
        }

        /// <summary>
        ///   注册一个删除的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <typeparam name="TKey">实体主键类型</typeparam>
        /// <param name="entity"> 要注册的对象 </param>
        public void RegisterDeleted<TEntity>(TEntity entity) where TEntity : class, IDbEntity
        {
            Context.Entry(entity).State = EntityState.Deleted;
            IsCommitted = false;
        }

        /// <summary>
        ///   批量注册多个删除的对象到仓储上下文中
        /// </summary>
        /// <typeparam name="TEntity"> 要注册的类型 </typeparam>
        /// <typeparam name="TKey">实体主键类型</typeparam>
        /// <param name="entities"> 要注册的对象集合 </param>
        public void RegisterDeleted<TEntity>(IEnumerable<TEntity> entities) where TEntity : class, IDbEntity
        {
            try
            {
                Context.Configuration.AutoDetectChangesEnabled = false;
                foreach (TEntity entity in entities)
                {
                    RegisterDeleted<TEntity>(entity);
                }
            }
            finally
            {
                Context.Configuration.AutoDetectChangesEnabled = true;
            }
        }


    }

}
